KMM 的多層結構會強制我們把一個 app 分成很多個 module,不過就算不是 KMM 的專案也是有很高的機率會把專案拆成多個 module 來降低彼此耦合度、提升 build performance 等。但通常技術本身不會只有好處而沒有缺點的,multi-module 專案的其中一個麻煩就是管理 dependency 的版本。
比如說有好多個 module 都同時使用了 ktor 或是 koin,很自然的我們會想要讓他們都使用同一個版本避免版本衝突出現問題。
這個問題並不是沒有解法,其中一個方法是可以在 root project 的 build.gradle 定義一些共用的變數,然後就可以把版本等資訊都統一集中管理讓其他地方使用,簡單範例如下:
// Root build.gradle
ext {
ktorVersion = "2.1.0"
}
// Each module usage
implementation "io.ktor:ktor-client-core:${rootProject.ext.ktorVersion}"
implementation "io.ktor:ktor-client-cio:${rootProject.ext.ktorVersion}"
看起來問題好像解決了,但有沒有更好的方法呢?
看標題其實就知道我們接下來要講 buildSrc 了,首先,buildSrc 並不只是管理版本的工具,它其實就像一般的程式碼一樣可以做五花八門的事情,但以管理版本這個需求入門 buildSrc 也是個非常好的開始。
只要在專案的第一層建立名為 buildSrc 的資料夾,然後裡面結構其實跟其他的 module 差不多,只是 build project 的時候,這個 module 會作為 build script 的一部分,所以我們可以在 build.gradle(.kts) 中拿到這邊定義的資料,而一個 project 只能有一個 buildSrc,也就很自然的成為了 single source of truth 了。
大概的結構會如下所示:
├── buildSrc
│ ├── build.gradle.kts
│ └── src
│ ├── main
│ │ └── java
│ │ ├── Versions.kt
│ │ ├── Libraries.kt
│ │ └── ...
│ └── test
│ └── java
│ └── ...
以下我們介紹一下各個檔案大致怎麼寫,首先是 buildSrc 的 build.gradle.kts:
import org.gradle.kotlin.dsl.`kotlin-dsl`
plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
}
主要只是 apply 了 kotlin-dsl 的 plugin 而已,其他就看大家需求也可以加其他 dependency。
再來是 Versions.kt 跟 Libraries.kt:
object Versions {
const val coreKtx = "1.7.0"
...
}
object Libraries {
const val coreKtx = "androidx.core:core-ktx:${Versions.coreKtx}"
...
}
可以看得出來跟寫一般的程式沒二樣啊,先在 Versions
定義了版本,然後在 Libraries
裡定義 dependency 加上版本的 reference。
使用的方式也很簡單,如下:
dependencies {
implementation(Libraries.coreKtx)
...
}
有了自動完成寫起來是不是更流暢呢?其實筆者也是近期才開始學習 buildSrc,歡迎留言跟我說你的想法。
buildSrc 的結構 Libraries.java 是筆誤對嗎?
應該是 Libraries.kt 對吧?
感謝火眼金睛